// X86Translator.cpp, // Implement class X86Translator
#include "crossbit/common.h"
#include "crossbit/X86Translator.h"
#include "crossbit/VBlock.h"
#include "crossbit/VInst.h"
#include "crossbit/Interpreter.h"
#include "crossbit/TBlock.h"
#include "X86.h"

using namespace crossbit;
volatile MemAddr X86Translator::ReturnAddress = 0;
TBlock* X86Translator::ExitFromBlock = NULL;

struct X86Translator::RegisterFile X86Translator::saved_; 

X86Translator::X86Translator(ProcessorState *state) 
    :Translator(state), firstTime_(true), /* spillPool_(NULL),*/ inst_(NULL) ,fpWordcount(0),fpDwordcount(0)
{
    // tblock related initialization is done in "initTranslation"
    spillPool_ = (Word *)malloc(100 * sizeof(Word));
    memset((void *)spillPool_, 0, 100 * sizeof(Word));
}

X86Translator::~X86Translator()
{
    if (spillPool_)
	free(spillPool_);

    //added by zhengjuyu
    //set the fpu control word to under flow
}

void X86Translator::initTranslation() 
{
    vinstSeq_ = 0;
    nextUseTbl_.clear();
    toReleaseRegs_.clear();
    freeRegs_.clear();
    vRegUsgTbl_.clear();
    tRegUsgTbl_.clear();

    for (RegNum i = 0; i < 8; i++) {
	freeRegs_.insert(i);
	struct RegUsage ru; 
	ru.status = FREE;
	ru.map = 0;
	ru.inst = 0;
	tRegUsgTbl_.insert(std::make_pair(i, ru));
    }

    instBuf_ = (char *)(tblock_->enterAddr());

    X86::setP(reinterpret_cast<char *>(tblock_->enterAddr()));

    // save the esp value, for the first time
    if(firstTime_) {
	firstTime_ = false;
	X86::movw_reg_to_mem(X86::ESP, (MemAddr)&savedESP_);
    }

    // Initialize the variables for LOOP and LABEL
    loopAddr[0] = -1;
    loopAddr[1] = -1;
    labelAddr[0] = -1;
    labelAddr[1] = -1;
}

void X86Translator::collectNextUseInfo()
{
    std::map<RegNum, int> nu;
    VBlock::const_reverse_iterator I = vblock_->rbegin(),
				   E = vblock_->rend();
    int nv = vblock_->size();
    struct RegUsage ru;
    ru.status = UNMAPPED;
    ru.map = 0;
    ru.inst = 0;

    // int vregMax = 0;
    for (; I != E; ++I, --nv) {
	VInst *inst = *I;
	int n = inst->getOperandNum();
	nextUseTbl_.push_front(nu);

	// _reverse_ iterate the operand, so that operands DEFed 
	// will be handled prior to operands USEed
	for (int i = n; i >= 1; --i) {
	    Operand opr = inst->getOperand(i);
	    RegNum r;

	    if(opr.type == Operand::VREG_USE ||
	       opr.type == Operand::VREG_DEF) {
	//	if (opr.reg > vregMax)
	//	    vregMax = opr.reg;
		
		if (opr.type == Operand::VREG_USE) {
		    r = opr.reg;
		    nu[r] = nv;
		}

		if (opr.type == Operand::VREG_DEF) {
		    r = opr.reg;
		    std::map<RegNum, int>::iterator it = 
			nu.find(r);
		    if (it != nu.end())
			nu.erase(it);
		}
	    }
	    if (vRegUsgTbl_.find(r) == vRegUsgTbl_.end())
		vRegUsgTbl_.insert(std::make_pair(r, ru));
	}

	// remove special v0
	nu.erase(0);
    }

    //spillPoolSize_ = (vregMax+1) * sizeof(Word);
    //LF("vregMax = %d\n", % vregMax);
}

void X86Translator::printNextUseInfo() 
{
    NextUseTable::const_iterator I = nextUseTbl_.begin(),
				 E = nextUseTbl_.end();
    int line = 1;
    
    for (; I != E; ++I, ++line) {
	std::map<RegNum, int>::const_iterator 
	    i = I->begin(),
	    e = I->end();

	std::cout << line << ": ";
	for (; i != e; ++i)
	    std::cout << i->first << "," << i->second << " ";
	std::cout << std::endl;
    }
}

// Allocate target register for virtual register
RegNum X86Translator::regAlloc(RegNum vreg, RegAccessMode mode)
{
    LGF("REGALLOC","Allocate register for v%d, at i%d\n", % vreg % vinstSeq_);
    std::map<RegNum, int> nu = nextUseTbl_[vinstSeq_];
    struct RegUsage &vru = vRegUsgTbl_[vreg];

    RegNum alloc;
    if (vru.status == MAPPED) {
	LGF("REGALLOC", "\tv%d is already mapped to t%d\n", % vreg % vru.map);
	alloc = vru.map;
    } 
    else {  // UMAPPED or SPILLED
	// First of all, find an available target register
	if (! freeRegs_.empty()) {   // free target registers available
	    alloc = *(freeRegs_.begin());
	    freeRegs_.erase(freeRegs_.begin());
	    LGF("REGALLOC", "\tt%d is allocated for v%d\n", % alloc % vreg);
	} 
	else {
	    // find ALLOCATED target register whose mapped virtual regiser 
	    // has the furthest next-use
	    LG("REGALLOC", "\tthere are free registers...");
	    int maxNextUseValue = 0;
	    RegNum maxNextUseReg = 0;
	    RegUsageTable::const_iterator I = tRegUsgTbl_.begin(),
					  E = tRegUsgTbl_.end();
	    for (; I != E; ++I) {
		struct RegUsage tru = I->second;
		if (tru.status != ALLOCATED || // RESERVED/FREE registers cannot be spilled out
		    tru.inst == vinstSeq_)     // we cannot spill out reg allocated to current inst.
		    continue;
		if (nu[tru.map] > maxNextUseValue) {
		    maxNextUseValue = nu[tru.map];
		    maxNextUseReg = I->first;
		}
	    }
	    LGF("REGALLOC", "t%d which is mapped to v%d is the victim to be spilled out\n", 
	        % maxNextUseReg % tRegUsgTbl_[maxNextUseReg].map);
	    alloc = regSpillOut(tRegUsgTbl_[maxNextUseReg].map);
	}

	if (vru.status == SPILLED)
	    regSpillIn(vreg, alloc);

	vru.status = MAPPED;
	vru.map = alloc;

	tRegUsgTbl_[alloc].status = ALLOCATED;
	tRegUsgTbl_[alloc].map = vreg;

	if (alloc == X86::ESP)
	    dirtyESP_ = true;
    }

    unmapIfNoNextUse(vreg);

    tRegUsgTbl_[alloc].inst = vinstSeq_;

    return alloc;
}

void X86Translator::unmapIfNoNextUse(RegNum vreg)
{
    struct RegUsage &vru = vRegUsgTbl_[vreg];
    std::map<RegNum, int> nu = nextUseTbl_[vinstSeq_];

    if (nu.find(vreg) == nu.end()) {	// no next uses
	// target register will be released after 
	// the current instruction finishes execution
	toReleaseRegs_.push_back(vru.map);
    }
}

RegNum X86Translator::regSpillOut(RegNum vreg)
{
//    LF("! spill out v%d\n", % vreg);
    assert(vRegUsgTbl_[vreg].status == MAPPED);

    RegNum treg = vRegUsgTbl_[vreg].map;
    X86::movw_reg_to_mem(treg, (MemAddr)(spillPool_ + vreg));

    // !! we do not release the target register, since it is always
    // RESERVED or ALLOCATED after we spill the vreg.
    //
    // freeRegs_.insert(treg);
    // tRegUsgTbl_[vRegUsgTbl_[vreg].map].status = FREE;
    // tRegUsgTbl_[vRegUsgTbl_[vreg].map].map = 0;
    //
    vRegUsgTbl_[vreg].status = SPILLED;
    vRegUsgTbl_[vreg].map = 0;

    return treg;
}

void X86Translator::regSpillIn(RegNum vreg, RegNum treg)
{
//    LF("! spill in v%d from t%d\n", % vreg % treg);
    // !! we simply load vreg from spill pool to treg,
    // !! other housekeeping things must be done by the caller
    X86::movw_mem_to_reg((MemAddr)(spillPool_ + vreg), treg);
}

// Force allocate target register "expect" to "vreg"
//
// Algorithms:
//  if (vreg is already allocated to expect)
//	return immediately
//  else 
//	empty "expect" register for "Vreg";
//	if (vreg is currently allocated to another target register)
//	    move it to "expect"
//	if (vreg is spilled)
//	    load vreg from spill pool to expect
//	...
// 
RegNum X86Translator::regAllocForce(RegNum vreg, RegNum expect, RegAccessMode mode)
{
    struct RegUsage &vru = vRegUsgTbl_[vreg],
		    &eru = tRegUsgTbl_[expect];

//    LF("regAllocForce: [enter] vreg: %d(%d, %d), expect: %d\n", 
//	    % vreg % vru.status % vru.map % expect);
    assert(eru.status != RESERVED); // dead-lock

    if (vru.status != MAPPED || vru.map != expect) {
	if (eru.status == FREE)
	    freeRegs_.erase(freeRegs_.find(expect));
	else if (eru.status == ALLOCATED) {
//	    LF("regAllocForce: the expected treg(%d) is ocuppyied by v%d, spill it out\n", % expect % eru.map);
	    regSpillOut(eru.map);
	}

	if (vru.status == MAPPED /* but vru.map != expect */) {
//	    LF("regAllocForce: vreg(%d) is already mapped, so just move it out of t%d to t%d\n", 
//		    % vreg % vru.map % expect);
	    struct RegUsage &tru = tRegUsgTbl_[vru.map];
	    freeRegs_.insert(vru.map);
	    tru.status = FREE;
	    tru.map = 0;
	    X86::movw_reg_to_reg(vru.map, expect);
	}

	if (vru.status == SPILLED) {
//	    LF("regAllocForce: v%d is SPILLED, spilled it in to t%d\n", % vreg % expect);
	    regSpillIn(vreg, expect);
	}

	vru.status = MAPPED;
	vru.map = expect;
	eru.status = ALLOCATED;
	eru.map = vreg;

	if (expect == X86::ESP)
	    dirtyESP_ = true;
    }

    unmapIfNoNextUse(vreg);

    eru.inst = vinstSeq_;

    return expect;
}

// Force "vreg" NOT to be allocated to "except"
//
// Algorithm:
//	if vreg is already allocated and it's not "except"
//	    return immediately
//	else 
//	    "reserve" "except" register
//	    alloc = regAlloc(vreg, mode)
//	    "release" "except" register
//
RegNum X86Translator::regAllocForceExcept(RegNum vreg, RegNum except, RegAccessMode mode)
{
    //LF("regAllocForceExcept: vreg: v%d, except: t%d\n", % vreg % except);

    struct RegUsage &eru = tRegUsgTbl_[except],
		    &vru = vRegUsgTbl_[vreg];

    RegNum alloc = 0;
    if (vru.status == MAPPED && vru.map != except)
	alloc = vru.map;
    else {
	if (vru.status == MAPPED /* && vru.map == except */) {
//	    LF("regAllocForceExcept: v%d is mapped to t%d, spill it out\n", 
//		    % vreg % except);
	    regSpillOut(vreg);
	    eru.status = FREE;
	    freeRegs_.insert(except);
	}

	bool reserve = false;
	if (eru.status == FREE) {
	    regAllocReserve(except);
	    reserve = true;
	}

	alloc = regAlloc(vreg, mode);
//	LF("regAllocForceExcept: v%d is allocated to t%d\n", % vreg % alloc);

	if (reserve)
	    regAllocRelease(except);
    }

    unmapIfNoNextUse(vreg);
    return alloc;
}

void X86Translator::regAllocReserve(RegNum treg)
{
    struct RegUsage &tru = tRegUsgTbl_[treg];

    assert(tru.status != RESERVED && "regAllocReserve");
    if (tru.status == FREE)
	freeRegs_.erase(freeRegs_.find(treg));
    else    // ALLOCATED
	regSpillOut(tru.map);

    tru.status = RESERVED;
    tru.map = 0;
    return;
}

void X86Translator::regAllocRelease(RegNum treg)
{
    struct RegUsage &tru = tRegUsgTbl_[treg];
    assert(tru.status == RESERVED);

    freeRegs_.insert(treg);
    tru.status = FREE;
    tru.map = 0;
    return;
}

RegNum X86Translator::regAllocForCall(RegNum vreg, RegAccessMode mode)
{
    struct RegUsage &vru = vRegUsgTbl_[vreg];

    RegNum alloc = 0;
    if (vru.status == MAPPED)
	alloc = vru.map;
    else {
        regAllocReserve(X86::EAX);
    	regAllocReserve(X86::ECX);
	regAllocReserve(X86::EDX);

	alloc = regAlloc(vreg, mode);

    	regAllocRelease(X86::EDX);
	regAllocRelease(X86::ECX);
	regAllocRelease(X86::EAX);
    }

    unmapIfNoNextUse(vreg);
    return alloc;
}

void X86Translator::setBlockStub()
{
    X86::mov_imm_to_mem((MemAddr)tblock_, (MemAddr)(&ExitFromBlock), WORD);
}

// we implement a lightweight x86 encoder
void X86Translator::encode(VBlock *vblock, TBlock *tblock)
{
    this->vblock_ = vblock;
    this->tblock_ = tblock;

    initTranslation();

    // 1. Instruction selection
    //
    // Currently, we trivially do any work for "instruction selection":
    // each VInst is encoded into x86 codes individually,
    // resulting in poor quality of generated code, yet simplifying the job of encoder
    // and also reducing the runtime overhead caused by sophisticated instruction
    // selection algorithms.
    //
    // 2. Collect usage counts information
    //
    // We used a simple register allocation algorithm based on usage counts.
    
    // usageCount();
    collectNextUseInfo();
    // printNextUseInfo();

    //spillPool_ = (volatile Word *)realloc((void *)spillPool_, spillPoolSize_);
    //memset((void *)spillPool_, 0, spillPoolSize_);

    setBlockStub();

    // 3. Encode
    for (VBlock::iterator it = vblock_->begin(); it != vblock_->end(); ++it, ++vinstSeq_) {
//	LF("*** encoding instruction seq no: %d\n", % vinstSeq_);
	inst_ = *it;
	Opcode op = inst_->getOpcode();

	switch (op) {
	    case OP_GET:    encodeGET();    break;
	    case OP_PUT:    encodePUT();    break;
	    case OP_LD:	    encodeLD();	    break;
	    case OP_ST:	    encodeST();	    break;
	    case OP_LI:	    encodeLI();	    break;
	    case OP_MOV:    encodeMOV();    break;

	    case OP_SEXT:   encodeSEXT();   break;
	    case OP_ZEXT:   encodeZEXT();   break;
	    case OP_ADD:    encodeADD();    break; 
	    case OP_SUB:    encodeSUB();    break;
	    case OP_ADDI:   encodeADDI();    break; 
	    case OP_SUBI:   encodeSUBI();    break;
	    case OP_AND:    encodeAND();    break; 
	    case OP_XOR:    encodeXOR();    break; 
	    case OP_OR:	    encodeOR();	    break;
	    case OP_NOT:    encodeNOT();    break;
	    case OP_SLL:    encodeSLL();    break;   
	    case OP_SRL:    encodeSRL();    break;
	    case OP_SRA:    encodeSRA();    break;
	    /*
	    case OP_SLLV:   encodeSLLV();   break;
	    case OP_SRLV:   encodeSRLV();   break;
	    case OP_SRAV:   encodeSRAV();   break;
	    */
	    case OP_MUL:    encodeMUL();    break; 
	    case OP_MULU:   encodeMULU();   break;
	    case OP_DIV:    encodeDIV();    break;
	    case OP_DIVU:   encodeDIVU();   break;

	    case OP_CMP:    encodeCMP();    break;
	    case OP_BRANCH: encodeBRANCH();    break;
	    case OP_JMP:    encodeJMP();    break;
	    case OP_HALT:   encodeSBREAK(); break;
	    case OP_SYSCALL:encodeSYSCALL();break;
	    case OP_CALL:   encodeCALL();   break;
	    case OP_LOOP:   encodeLOOP();   break;
	    case OP_LOOPN:   encodeLOOPN();   break;
	    case OP_LABEL:  encodeLABEL();   break;
	    case OP_USE:  encodeUSE();   break;
	    
	    case OP_FPUT_S:   encodeFPUTS();   break;
	    case OP_FGET_S:   encodeFGETS();   break;
	    case OP_FPUT_D:   encodeFPUTD();   break;
	    case OP_FGET_D:   encodeFGETD();   break;

	    case OP_FLD:   encodeFLD();   break;
	    case OP_FST:   encodeFST();   break;
	    case OP_FMOV:   encodeFMOV();    break;

	    case OP_FCOS:  encodeFCOS();   break;
	    case OP_FPTAN:  encodeFPTAN();   break;
	    case OP_FSIN:  encodeFSIN();   break;
	    case OP_FCHS:  encodeFCHS();   break;
	    case OP_FSCALE:  encodeFSCALE();   break;
	    case OP_F2XM1:  encodeF2XM1();   break;
	    case OP_FYL2X:   encodeFYL2X(); break;
	    case OP_FYL2XP1:   encodeFYL2XP1(); break;
	    case OP_FLDL2E:   encodeFLDL2E(); break;
	    case OP_FLDLG2:   encodeFLDLG2(); break;
	    case OP_FLDLN2:   encodeFLDLN2(); break;
	    case OP_FXAM:   encodeFXAM(); break;
	    case OP_FRNDINT: encodeFRNDINT(); break;
	    case OP_FADD_S:    encodeFADDS();    break;
	    case OP_FADD_D:    encodeFADDD();    break;
            case OP_FSUB_S:    encodeFSUBS();    break;
            case OP_FSUB_D:    encodeFSUBD();    break;
            case OP_FMUL_S:    encodeFMULS();    break;
            case OP_FMUL_D:    encodeFMULD();    break;
            case OP_FDIV_S:    encodeFDIVS();    break;
            case OP_FDIV_D:    encodeFDIVD();    break;
            case OP_FNEG_S:    encodeFNEGS();    break;
            case OP_FNEG_D:    encodeFNEGD();    break;
            case OP_FABS_S:    encodeFABSS();    break;
            case OP_FABS_D:    encodeFABSD();    break;
            case OP_FSQRT_S:    encodeFSQRTS();    break;
            case OP_FSQRT_D:    encodeFSQRTD();    break;
            case OP_FCMP_S:    encodeFCMPS();    break;
            case OP_FCMP_D:    encodeFCMPD();    break;

            case OP_FCONV:    encodeFCONV();    break;
	    case OP_FINCSTP: encodeFINCSTP();	break;
	    case OP_BSR:     encodeBSR();       break;
	    case OP_BSF:     encodeBSF(); 	break;
	    case OP_DIVU64:  encodeDIVU64();	break;

	    default:
		assert(0 && "Unrecognized opcode");
	}// end switch
	// take care of the toFreeRegisters
	std::vector<RegNum>::iterator it = toReleaseRegs_.begin();
	for (; it != toReleaseRegs_.end(); ++it) {
	    RegNum treg = *it;
	    struct RegUsage &tru = tRegUsgTbl_[treg],
			    &vru = vRegUsgTbl_[tru.map];

	    freeRegs_.insert(treg);
	    tru.status = FREE;
	    tru.map = 0;
	    vru.status = UNMAPPED;
	    vru.map = 0;
	}
	toReleaseRegs_.clear();
    }// end for

    // add Into-ExecEngine jump and END_OF_BLOCK exit 
    // if the last instruction is not unconditional jump
    if ( ! (inst_->getOpcode() == OP_JMP)) 
	endOfBlock();
    
    // encode all the TBlock Exits
    encodeExits();

    // set target code block size
    tblock_->setSize(X86::getP() - instBuf_);
}

void X86Translator::endOfBlock()
{
    X86::jmp_relative_direct_disp32(0);	// displacement will be back-patched later
    addTBlockExit(TBlock::ExitReason::ENDOFBLOCK, 
		  vblock_->nextSPC(),	
		  X86::getP() - 4 - instBuf_,
		  NULL);
}

int X86Translator::addTBlockExit(int why, MemAddr next, int exitOffset, VInst *inst)
{
    TBlock::Exit exit;
    exit.why = why;
    exit.next = next;
    exit.exitOffset = exitOffset;
    exit.inst = inst;
    return tblock_->putExit(exit);
}

TBlock *X86Translator::headBlock()
{
    class X86HeadTBlock : public TBlock {
	public:
	    X86HeadTBlock()
		:TBlock((MemAddr)(new char[11 /* see below */]), 
			vblock_)
	    {
	    }

	    ~X86HeadTBlock()
	    {
		delete [] (char *)(buf_);
	    }
    };

    tblock_ = new X86HeadTBlock();

    X86::setP(reinterpret_cast<char *>(tblock_->enterAddr()));

    // We want to assign the "return address" to ReturnAddress.
    // The return address is pushed to stack when this function is called,
    // so we just have to copy the value currently on the top of the stack 
    // to ReturnAddress. The assembly is as follows:
    //
    // [2] mov    %esp,%eax
    // [2] mov    (%eax),%eax
    // [6] mov    %eax,&ReturnAddress
    // [1] ret
    //
    // Exactly 11 bytes.
    
    X86::movw_reg_to_reg(X86::ESP, X86::EAX);
    X86::movw_mem_to_reg(X86::EAX, X86::EAX);
    X86::movw_reg_to_mem(X86::EAX, (MemAddr)&ReturnAddress);
    X86::ret();
    
    addTBlockExit(TBlock::ExitReason::HEAD, (MemAddr)0, 0, NULL);

    return tblock_;
}

void X86Translator::encodeExits()
{
    //added by Zheng, Juyu
    //for debugging purpose
    if( tblock_->countExit() == 0 )
            endOfBlock();


    for (int i = 0, num = tblock_->countExit(); i < num; ++i) {
	TBlock::Exit &e = tblock_->getExit(i);
	*(Word *)(instBuf_ + e.exitOffset) = X86::getP() - (instBuf_ + e.exitOffset + 4);
	
	// mov i<which Exit>, &TBlock::lastExit_
	// jmp rel32
	X86::movw_imm_to_mem(i, tblock_->getAddrOfLastExit());

	//mov e.next to edx, for indirect trace linking
	X86::movw_mem_to_reg((MemAddr)(&e.next), X86::EDX);

#if 0
	X86::jmp_relative_direct_disp32(ReturnAddress - 
				        ((MemAddr)X86::getP()
					+ 5) /* jmp rel32 is exactly 5 bytes long */ );
#endif

	// restore ESP and ret
	if (dirtyESP_) {
	    X86::movw_mem_to_reg((MemAddr)(&savedESP_), X86::ESP); 
	}

	e.linked = 0;
	e.linkCode = X86::getP();

	X86::ret();
	//added by zhengjuyu, reserve 5 words for nop
	X86::word(0x90909090);
	X86::nop();

	// tblock_->addRelocationPoint((X86::getP() - 4)- instBuf_);
    }
}

void X86Translator::encodeGET()
{
    // DEBUG(std::cerr << "  Encoding GET" << std::endl);
    // GET s, v
    //XXX mickey
    RegNum	src = inst_->getOperand(1).reg;
    BlockSize	size = inst_->getOperand(2).size;
    RegNum	reg = inst_->getOperand(3).reg;
    assert(reg != 0);

    switch(size)
    {
	case BYTE:
	{
	    if(src >= 0 && src <=3)
	    {
		MemAddr addr = srcState_->get(src);
		X86::movb_mem_to_reg(addr, regAlloc(reg, DEF));
	    }   
	    else if(src >=4 && src<=7)
	    {
		MemAddr addr = (MemAddr)(srcState_->get(src-4) + 1); //XXX 
		X86::movb_mem_to_reg(addr, regAlloc(reg, DEF));
	    }   
	    break;
	}
	case HALFWORD:
	{
	    MemAddr addr = srcState_->get(src);
	    X86::movh_mem_to_reg(addr, regAlloc(reg, DEF));
	    break;
	}
	case WORD:
	{
	    MemAddr addr = srcState_->get(src);
	    X86::movw_mem_to_reg(addr, regAlloc(reg, DEF));
	    break;
	}
    }
    
}

// PUT v, s
void X86Translator::encodePUT()
{
    // DEBUG(std::cerr << "  Encoding PUT" << std::endl);
    RegNum	reg = inst_->getOperand(1).reg;
    BlockSize	size = inst_->getOperand(2).size;
    RegNum	dst = inst_->getOperand(3).reg;

    switch(size)
    {
	case BYTE:
	{
	    if(dst >= 0 && dst <=3)
	    {
		MemAddr addr = srcState_->get(dst);

		if (reg == 0)
		    X86::movb_imm_to_mem(reg, addr);
		else
		    X86::movb_reg_to_mem(regAlloc(reg, USE), addr);
	    }
	    else if(dst >=4 && dst<=7)
	    {
		MemAddr addr = (MemAddr)(srcState_->get(dst-4) + 1); //XXX 

	 	if (reg == 0)
		    X86::movb_imm_to_mem(reg, addr);
		else
		    X86::movb_reg_to_mem(regAlloc(reg, USE), addr);
	    }
	    break;
	}
	case HALFWORD:
	{
	    MemAddr addr = srcState_->get(dst);

	    if (reg == 0)
		X86::movh_imm_to_mem(reg, addr);
	    else
		X86::movh_reg_to_mem(regAlloc(reg, USE), addr);
	   
	    break;
	}
	case WORD:
	{
	    MemAddr addr = srcState_->get(dst);

	    if (reg == 0)
		X86::movw_imm_to_mem(reg, addr);
	    else
		X86::movw_reg_to_mem(regAlloc(reg, USE), addr);

	    break;
	}
    }
}

#if 0
void X86Translator::encodeGET()
{
    // DEBUG(std::cerr << "  Encoding GET" << std::endl);
    // GET s, v
    //XXX mickey
    RegNum src = inst_->getOperand(1).reg;
    RegNum reg = inst_->getOperand(2).reg;
    assert(reg != 0);

    if(src >= 80 && src <=83)
    {
    	MemAddr addr = srcState_->get(src-80);
    	X86::movb_mem_to_reg(addr, regAlloc(reg, DEF));
    }
    else if(src >=84 && src<=87)
    {
    	MemAddr addr = (MemAddr)(srcState_->get(src-84) + 1); //XXX 
    	X86::movb_mem_to_reg(addr, regAlloc(reg, DEF));
    }
    else
    {
        MemAddr addr = srcState_->get(src);
    	X86::movw_mem_to_reg(addr, regAlloc(reg, DEF));
    }
}

/*
void X86Translator::encodeFGET()
{
    MemAddr addr = srcState_->get(inst_->getOperand(1).reg);
    X86::fld(addr);
}
*/

// PUT v, s
void X86Translator::encodePUT()
{
    // DEBUG(std::cerr << "  Encoding PUT" << std::endl);
    RegNum reg = inst_->getOperand(1).reg;

    //XXX mickey
    RegNum dst = inst_->getOperand(2).reg;
    if(dst >= 80 && dst <=83)
    {
    	MemAddr addr = srcState_->get(dst-80);

    	if (reg == 0)
		X86::movb_imm_to_mem(reg, addr);
	else
		X86::movb_reg_to_mem(regAlloc(reg, USE), addr);
    }
    else if(dst >=84 && dst<=87)
    {
    	MemAddr addr = (MemAddr)(srcState_->get(dst-84) + 1); //XXX 

    	if (reg == 0)
		X86::movb_imm_to_mem(reg, addr);
	else
		X86::movb_reg_to_mem(regAlloc(reg, USE), addr);
    }
    else
    {
    	MemAddr addr = srcState_->get(dst);

	if (reg == 0)
		X86::movw_imm_to_mem(reg, addr);
   	 else
		X86::movw_reg_to_mem(regAlloc(reg, USE), addr);
    }
}
#endif

/*
void X86Translator::encodeFPUT()
{
    MemAddr addr = srcState_->get(inst_->getOperand(1).reg);
    X86::fstp(addr);
}

void X86Translator::encodeFADD()
{
    X86::faddp1();
}

void X86Translator::encodeLD_S()
{
    RegNum	reg	= inst_->getOperand(1).reg;
    Word	disp	= inst_->getOperand(2).imm;
    MemAddr addr = reg + disp;
    X86::fld(addr);
}
*/
// LI imm, v
void X86Translator::encodeLI()
{
    // DEBUG(std::cerr << "  Encoding LI" << std::endl);
    Word imm = inst_->getOperand(1).imm;
    RegNum reg = inst_->getOperand(2).reg;
    assert(reg != 0);

    X86::movw_imm_to_reg(imm, regAlloc(reg, DEF));
}

// LD addr, sz, v
void X86Translator::encodeLD()
{
    RegNum	reg	= inst_->getOperand(1).reg;
    Word	disp	= inst_->getOperand(2).imm;
    BlockSize	size	= inst_->getOperand(3).size;
    RegNum	dst	= inst_->getOperand(4).reg;

    //assert(dst != 0);

    RegNum Tdst;
    RegNum Tsrc;

    regAllocReserve(X86::ESP);
    regAllocReserve(X86::EBP);

    if( size == BYTE )
    {
	Tdst = regAllocForce(dst, X86::EBX, USE);

	if( reg != 0 )
	    Tsrc = regAllocForceExcept( reg, X86::ESP, USE );
	
	if (reg == 0)
	    X86::mov_mem_to_reg(disp + reg, size, Tdst);
	else
	    X86::mov_mem_to_reg( Tsrc, disp, size, Tdst);

    }
    else
    {
	if( reg != 0 )
	    Tsrc = regAllocForceExcept( reg, X86::ESP, USE );
	
	if (size == BYTE)
	{
	    // TODO: find a better solution
	    Tdst = regAllocForce(dst, X86::EBX, USE);
	}
	else
	    Tdst = regAlloc(dst, DEF);
	if (reg == 0)
	    X86::mov_mem_to_reg(disp + reg, size, Tdst);
	else
	    X86::mov_mem_to_reg( Tsrc, disp, size, Tdst);
    }
    
    regAllocRelease(X86::EBP);
    regAllocRelease(X86::ESP);
}
// ST v, sz, addr
void X86Translator::encodeST()
{
    RegNum	src	= inst_->getOperand(1).reg;
    BlockSize	size	= inst_->getOperand(2).size;
    RegNum	reg	= inst_->getOperand(3).reg;
    Word	disp	= inst_->getOperand(4).imm;

    regAllocReserve(X86::ESP);
    regAllocReserve(X86::EBP);

    if (src == 0) {
	if (reg == 0)
	    X86::mov_imm_to_mem(src, disp, size);
	else {
	    RegNum Treg = regAllocForceExcept(reg, X86::ESP, USE);
	    X86::mov_imm_to_mem(src, Treg, disp, size);
	}
    }
    else {
	RegNum Tsrc;
	if (size == BYTE)
	    // TODO: find a better solution
	    Tsrc = regAllocForce(src, X86::EBX, USE);
	else
	    Tsrc = regAlloc(src, USE);

	if (reg == 0)
	    X86::mov_reg_to_mem(Tsrc, size, disp);
	else {
	    RegNum Treg = regAllocForceExcept(reg, X86::ESP, USE);
	    assert(Treg != X86::ESP);
	    X86::mov_reg_to_mem(Tsrc, size, Treg, disp);
	}
    }
   
    regAllocRelease(X86::EBP);
    regAllocRelease(X86::ESP);
}

// MOV v, v
void X86Translator::encodeMOV()
{
    RegNum src = inst_->getOperand(1).reg;
    RegNum dst = inst_->getOperand(2).reg;

    assert(dst != 0);

    if (src == 0)
	X86::movw_imm_to_reg(0, regAlloc(dst, DEF));
    else
    {
	RegNum Tsrc = regAlloc(src, USE);
	X86::movw_reg_to_reg( Tsrc, regAlloc(dst, DEF));
    }
}

// SEXT v, sz, v
void X86Translator::encodeSEXT()
{
    RegNum src = inst_->getOperand(1).reg,
	   Tsrc = regAlloc(src, USE);
    BlockSize sz = inst_->getOperand(2).size;
    RegNum dst = inst_->getOperand(3).reg,
	   Tdst = regAlloc(dst, DEF);

    // It makes nosense src to be v0
    assert(src != 0 && dst != 0);

    if (sz == BYTE)
	X86::movsbl_reg_to_reg(Tsrc, Tdst);
    else if (sz == HALFWORD)
	X86::movswl_reg_to_reg(Tsrc, Tdst);
    else
	assert(0);
}

// ZEXT v, sz, v
void X86Translator::encodeZEXT()
{
    RegNum src = inst_->getOperand(1).reg,
	   Tsrc = regAlloc(src, USE);
    BlockSize sz = inst_->getOperand(2).size;
    RegNum dst = inst_->getOperand(3).reg,
	   Tdst = regAlloc(dst, DEF);

    // It makes nosense src to be v0, v1
    assert(src != 0 && dst != 0);
    if (sz == BYTE)
	X86::movzbl_reg_to_reg(Tsrc, Tdst);
    else if (sz == HALFWORD)
	X86::movzwl_reg_to_reg(Tsrc, Tdst);
    else
	assert(0);
}

// ADD v, v, v
void X86Translator::encodeADD()
{
    // DEBUG(std::cerr << "  Encoding ADD" << std::endl);
    RegNum src1 = inst_->getOperand(1).reg;
    RegNum src2 = inst_->getOperand(2).reg;
    RegNum dst	= inst_->getOperand(3).reg;

    assert(dst != 0);

    if (src1 == 0 && src2 == 0)
    {
	RegNum Tdst = regAlloc(dst, DEF);
	X86::movw_imm_to_reg(0, Tdst);
    }
    else if (src1 == 0) {
	RegNum Tsrc2 = regAlloc(src2, USE);
	RegNum Tdst = regAlloc(dst, DEF);
	if (src2 != dst)
	    X86::movw_reg_to_reg(Tsrc2, Tdst);
    } 
    else if (src2 == 0) {
	RegNum Tsrc1 = regAlloc(src1, USE);
	RegNum Tdst = regAlloc(dst, DEF);
	if (src1 != dst)
	    X86::movw_reg_to_reg(Tsrc1, Tdst);
    } 
    else {
	RegNum Tsrc1 = regAlloc(src1, USE);
	RegNum Tsrc2 = regAlloc(src2, USE);
	RegNum Tdst = regAlloc(dst, DEF);
	
	if (src1 == dst)
	    X86::add_reg_to_reg(Tsrc2, Tdst);
	else if (src2 == dst)
	    X86::add_reg_to_reg(Tsrc1, Tdst);
	else {
	    X86::movw_reg_to_reg(Tsrc1, Tdst);
	    X86::add_reg_to_reg(Tsrc2, Tdst); 
	}
    }
}

// ADDI v, imm, v
void X86Translator::encodeADDI()
{
    RegNum src1 = inst_->getOperand(1).reg;
    Word imm = inst_->getOperand(2).imm;
    RegNum dst	= inst_->getOperand(3).reg;
    
    RegNum Tsrc1 = regAlloc(src1, USE);
    RegNum Tdst = regAlloc(dst, DEF);
	
    if (src1 == dst) {
	if ( imm == 1)
	    X86::inc(Tdst);
	else if ( imm >= -128 && imm <= 127)
	    X86::add_imm8_to_reg((Byte)imm, Tdst);
	else
	    X86::add_imm_to_reg(imm, Tdst);
    } else {
    	X86::movw_reg_to_reg(Tsrc1, Tdst);

	if ( imm == 1)
	    X86::inc(Tdst);
	else if ( imm >= -128 && imm <=127)
	    X86::add_imm8_to_reg((Byte)imm, Tdst); 
	else
	    X86::add_imm_to_reg(imm, Tdst); 
    }
}

//XXX may have error
// SUB v, v, v
void X86Translator::encodeSUB()
{
    // DEBUG(std::cerr << "  Encoding SUB" << std::endl);
    RegNum src1 = inst_->getOperand(1).reg;
    RegNum src2 = inst_->getOperand(2).reg;
    RegNum dst	= inst_->getOperand(3).reg;

    assert(dst != 0);
    assert(!(src1 == 0 && src2 == 0));

    if (src1 == 0) {
	RegNum Tsrc2 = regAlloc(src2, USE);
	RegNum Tdst = regAlloc(dst, DEF);
	if (src2 != dst)
	    X86::movw_reg_to_reg(Tsrc2, Tdst);
	X86::neg_reg(Tdst);
    }
    else if (src2 == 0) {
	RegNum Tsrc1 = regAlloc(src1, USE);
	RegNum Tdst = regAlloc(dst, DEF);
	if (src1 != dst)
	    X86::movw_reg_to_reg(Tsrc1, Tdst);
    }
    else {
	RegNum Tsrc1 = regAlloc(src1, USE);
	RegNum Tsrc2 = regAlloc(src2, USE);
	RegNum Tdst = regAlloc(dst, DEF);

	if (src1 == dst) 
	    X86::sub_reg_from_reg(Tsrc2, Tsrc1);
	else if (src2 == dst)
	{
	    X86::sub_reg_from_reg(Tsrc1, Tsrc2);
	    X86::neg_reg(Tsrc2);
	}
	else {
	    X86::movw_reg_to_reg(Tsrc1, Tdst);
	    X86::sub_reg_from_reg(Tsrc2, Tdst);
	}
    }
}

// SUBI v, imm, v
void X86Translator::encodeSUBI()
{
    RegNum src1 = inst_->getOperand(1).reg;
    Word imm = inst_->getOperand(2).imm;
    RegNum dst	= inst_->getOperand(3).reg;

    RegNum Tsrc1 = regAlloc(src1, USE);
    RegNum Tdst = regAlloc(dst, DEF);
    
    if (src1 == dst) 
    {
	if (imm == 1)
	    X86::dec(Tsrc1);
	else if ( imm >= -128 && imm <= 127)
    	    X86::sub_imm8_from_reg((Byte)imm, Tsrc1);
	else
    	    X86::sub_imm_from_reg(imm, Tsrc1);
    }
    else
    {
    	X86::movw_reg_to_reg(Tsrc1, Tdst);

	if (imm == 1)
	    X86::dec(Tdst);
	else if ( imm >= -128 && imm <= 127)
       	    X86::sub_imm8_from_reg((Byte)imm, Tdst);
	else
       	    X86::sub_imm_from_reg(imm, Tdst);
    }
}

// AND v, v, v
void X86Translator::encodeAND()
{
    // DEBUG(std::cerr << "  Encoding AND" << std::endl);
    RegNum src1 = inst_->getOperand(1).reg;
    RegNum src2 = inst_->getOperand(2).reg;
    RegNum dst	= inst_->getOperand(3).reg;

    assert(dst != 0);
    // It makes nosense src1 and src2 to be
    // v0 at the same time.
    assert(! (src1 == 0 && src2 == 0));

    if (src1 == 0 || src2 == 0) {
	// 0 & ANY -> 0
	RegNum Tdst = regAlloc(dst, DEF);
	X86::movw_imm_to_reg(0, Tdst);
    } 
    else {
	RegNum Tsrc1 = regAlloc(src1, USE);
	RegNum Tsrc2 = regAlloc(src2, USE);
	RegNum Tdst = regAlloc(dst, DEF);

	if (src1 == dst)
	    X86::and_reg_to_reg(Tsrc2, Tdst);
	else if (src2 == dst)
	    X86::and_reg_to_reg(Tsrc1, Tdst);
	else {
	    X86::movw_reg_to_reg(Tsrc1, Tdst);
	    X86::and_reg_to_reg(Tsrc2, Tdst); 
	}
    }
}

// XOR v, v, v
void X86Translator::encodeXOR()
{
    // DEBUG(std::cerr << "  Encoding XOR" << std::endl);
    RegNum src1 = inst_->getOperand(1).reg;
    RegNum src2 = inst_->getOperand(2).reg;
    RegNum dst	= inst_->getOperand(3).reg;

    assert(dst != 0);
    // It makes nosense src1 and src2 to be
    // v0 at the same time.
    assert(! (src1 == 0 && src2 == 0));

    if (src1 == 0) {
	// 0 ^ ANY -> ANY
	RegNum Tsrc2 = regAlloc(src2, USE);
	RegNum Tdst = regAlloc(dst, DEF);
	if (src1 != dst)
	    X86::movw_reg_to_reg(Tsrc2, Tdst);
    } 
    else if (src2 == 0) {
	// ANY ^ 0 -> ANY
	RegNum Tsrc1 = regAlloc(src1, USE);
	RegNum Tdst = regAlloc(dst, DEF);
	if (src1 != dst)
	    X86::movw_reg_to_reg(Tsrc1, Tdst);
    } 
    else {
	RegNum Tsrc1 = regAlloc(src1, USE);
	RegNum Tsrc2 = regAlloc(src2, USE);
	RegNum Tdst = regAlloc(dst, DEF);

	if (src1 == dst)
	    X86::xor_reg_to_reg(Tsrc2, Tdst);
	else if (src2 == dst)
	    X86::xor_reg_to_reg(Tsrc1, Tdst);
	else {
	    X86::movw_reg_to_reg(Tsrc1, Tdst);
	    X86::xor_reg_to_reg(Tsrc2, Tdst); 
	}
    }
}

// OR v, v, v
void X86Translator::encodeOR()
{
    RegNum src1 = inst_->getOperand(1).reg;
    RegNum src2 = inst_->getOperand(2).reg;
    RegNum dst	= inst_->getOperand(3).reg;

    assert(dst != 0);
    // It makes nosense src1 and src2 to be
    // v0 at the same time.
    assert(! (src1 == 0 && src2 == 0));

    if (src1 == 0) {
	// 0 | ANY -> ANY
	RegNum Tsrc2 = regAlloc(src2, USE);
	RegNum Tdst = regAlloc(dst, DEF);

	if (src2 != dst)
	    X86::movw_reg_to_reg(Tsrc2, Tdst);
    } 
    else if (src2 == 0) {
	// ANY | 0 -> ANY
	RegNum Tsrc1 = regAlloc(src1, USE);
	RegNum Tdst = regAlloc(dst, DEF);

	if (src1 != dst)
	    X86::movw_reg_to_reg(Tsrc1, Tdst);
    } 
    else {
	RegNum Tsrc1 = regAlloc(src1, USE);
	RegNum Tsrc2 = regAlloc(src2, USE);
	RegNum Tdst = regAlloc(dst, DEF);

	if (src1 == dst)
	    X86::or_reg_to_reg(Tsrc2, Tdst);
	else if (src2 == dst)
	    X86::or_reg_to_reg(Tsrc1, Tdst);
	else {
	    X86::movw_reg_to_reg(Tsrc1, Tdst);
	    X86::or_reg_to_reg(Tsrc2, Tdst); 
	}
    }
}

// NOT v, v
void X86Translator::encodeNOT()
{
    RegNum src = inst_->getOperand(1).reg,
	   dst = inst_->getOperand(2).reg;

    assert(src != 0 && dst != 0);

    RegNum Tsrc = regAlloc(src, USE), 
	   Tdst = regAlloc(dst, DEF);

    if (src != 0) {
	if (src != dst)
	    X86::movw_reg_to_reg(Tsrc, Tdst);
	X86::not_reg(Tdst);
    }
    else
	X86::movw_imm_to_reg(0xffffffff, Tdst);
}

/*
// SLL v, imm, v
void X86Translator::encodeSLL()
{
    RegNum src = inst_->getOperand(1).reg,
	   dst = inst_->getOperand(3).reg;
    unsigned char shc = inst_->getOperand(2).imm;

    assert(src != 0 && dst != 0);

    RegNum Tsrc = regAlloc(src, USE),
	   Tdst = regAlloc(dst, DEF);

    if (src != dst)
	X86::movw_reg_to_reg(Tsrc, Tdst);
    X86::shl_reg_by_imm(Tdst, shc);
}
*/

// SLL v, v, v
void X86Translator::encodeSLL()
{
    RegNum src = inst_->getOperand(1).reg,
	   dst = inst_->getOperand(3).reg,
	   shc = inst_->getOperand(2).reg;

    assert(src != 0 && dst != 0 && shc != 0);

    // the allocation sequence is important:
    // shc must be allocated before src&dst, so that
    // src&dst will not use ECX
    regAllocForce(shc, X86::ECX, USE);
    RegNum Tsrc = regAlloc(src, USE),
	   Tdst = regAlloc(dst, DEF);

    if (src != dst) {
	X86::movw_reg_to_reg(Tsrc, Tdst);
    }
    X86::shl_reg_by_cl(Tdst);
}

/*
// SRL v, imm, v
void X86Translator::encodeSRL()
{
    RegNum src = inst_->getOperand(1).reg,
	   dst = inst_->getOperand(3).reg;
    unsigned char shc = inst_->getOperand(2).imm;

    assert(src != 0 && dst != 0);

    RegNum Tsrc = regAlloc(src, USE),
	   Tdst = regAlloc(dst, DEF);

    if (src != dst) 
	X86::movw_reg_to_reg(Tsrc, Tdst);
    X86::shr_reg_by_imm(Tdst, shc);
}
*/

// SRL v, v, v
void X86Translator::encodeSRL()
{
    RegNum src = inst_->getOperand(1).reg,
	   dst = inst_->getOperand(3).reg,
	   shc = inst_->getOperand(2).reg;

    assert(src != 0 && dst != 0 && shc != 0);

    regAllocForce(shc, X86::ECX, USE);
    RegNum Tsrc = regAlloc(src, USE),
	   Tdst = regAlloc(dst, DEF);

    if (src != dst)
	X86::movw_reg_to_reg(Tsrc, Tdst);
    X86::shr_reg_by_cl(Tdst);
}

/*
// SRA v, imm, v
void X86Translator::encodeSRA()
{
    RegNum src = inst_->getOperand(1).reg,
	   dst = inst_->getOperand(3).reg;
    unsigned char shc = inst_->getOperand(2).imm;

    assert(src != 0 && dst != 0);

    RegNum Tsrc = regAlloc(src, USE),
	   Tdst = regAlloc(dst, DEF);

    if (src != dst)
	X86::movw_reg_to_reg(Tsrc, Tdst);
    X86::sar_reg_by_imm(Tdst, shc);
}
*/

// SRLV src, shc, dst
void X86Translator::encodeSRA()
{
    RegNum src = inst_->getOperand(1).reg,
	   dst = inst_->getOperand(3).reg,
	   shc = inst_->getOperand(2).reg;

    assert(src != 0 && dst != 0 && shc != 0);

    regAllocForce(shc, X86::ECX, USE);
    RegNum Tsrc = regAlloc(src, USE),
	   Tdst = regAlloc(dst, DEF);

    if (src != dst)
	X86::movw_reg_to_reg(Tsrc, Tdst);
    X86::sar_reg_by_cl(Tdst);
}

// MUL src1, src2, dst1(hi), dst2(lo)
void X86Translator::encodeMUL()
{
    regAllocReserve(X86::EAX);
    regAllocReserve(X86::EDX);

    RegNum src1 = inst_->getOperand(1).reg,
	   src2 = inst_->getOperand(2).reg,
	   dst1 = inst_->getOperand(3).reg,
	   dst2 = inst_->getOperand(4).reg;

    // simplify the situation
    assert(src1 != 0 &&
	   src2 != 0 &&
	   dst1 != 0 &&
	   dst2 != 0 );
    
    RegNum Tsrc1 = regAlloc(src1, USE),
	   Tsrc2 = regAlloc(src2, USE),
	   Tdst1 = regAlloc(dst1, DEF),
	   Tdst2 = regAlloc(dst2, DEF);

    // EDX  :EAX  <- EAX  * reg
    // dst1 :dst2 <- src1 * src2
    X86::movw_reg_to_reg(Tsrc1, X86::EAX);
    X86::imul_eax_to_reg(Tsrc2);
    X86::movw_reg_to_reg(X86::EDX, Tdst1);
    X86::movw_reg_to_reg(X86::EAX, Tdst2);

    regAllocRelease(X86::EDX);
    regAllocRelease(X86::EAX);
}

// MULU v, v, v, v
void X86Translator::encodeMULU()
{
    regAllocReserve(X86::EAX);
    regAllocReserve(X86::EDX);

    RegNum src1 = inst_->getOperand(1).reg,
	   src2 = inst_->getOperand(2).reg,
	   dst1 = inst_->getOperand(3).reg,
	   dst2 = inst_->getOperand(4).reg;

    // simplify the situation
    assert(src1 != 0 &&
	   src2 != 0 &&
	   dst1 != 0 &&
	   dst2 != 0 );
    
    RegNum Tsrc1 = regAlloc(src1, USE),
	   Tsrc2 = regAlloc(src2, USE),
	   Tdst1 = regAlloc(dst1, DEF),
	   Tdst2 = regAlloc(dst2, DEF);

    // EDX  :EAX  <- EAX  * reg
    // dst1 :dst2 <- src1 * src2
    X86::movw_reg_to_reg(Tsrc1, X86::EAX);
    X86::mul_eax_to_reg(Tsrc2);
    X86::movw_reg_to_reg(X86::EDX, Tdst1);
    X86::movw_reg_to_reg(X86::EAX, Tdst2);

    regAllocRelease(X86::EDX);
    regAllocRelease(X86::EAX);
}

// DIV v, v, v, v
void X86Translator::encodeDIV()
{
    regAllocReserve(X86::EAX);
    regAllocReserve(X86::EDX);

    RegNum src1 = inst_->getOperand(1).reg,
	   src2 = inst_->getOperand(2).reg,
	   dst1 = inst_->getOperand(3).reg,
	   dst2 = inst_->getOperand(4).reg;

    assert(src1 != 0 &&
	   src2 != 0 &&
	   dst1 != 0 &&
	   dst2 != 0 );
    
    RegNum Tsrc1 = regAlloc(src1, USE),
	   Tsrc2 = regAlloc(src2, USE),
	   Tdst1 = regAlloc(dst1, DEF),
	   Tdst2 = regAlloc(dst2, DEF);

    // EAX(quotient):EDX(remainder) <- EDX:EAX / reg
    // dst1         :dst2           <- src1    / src2
    X86::movw_reg_to_reg(Tsrc1, X86::EAX);
    X86::movw_reg_to_reg(X86::EAX, X86::EDX);
    X86::and_imm_to_reg(0x80000000, X86::EDX);
    X86::sar_reg_by_imm(X86::EDX, 31);
    X86::idiv_edx_eax_by_reg(Tsrc2);
    X86::movw_reg_to_reg(X86::EAX, Tdst1);
    X86::movw_reg_to_reg(X86::EDX, Tdst2);

    regAllocRelease(X86::EDX);
    regAllocRelease(X86::EAX);
}

// DIVU v, v, v, v
void X86Translator::encodeDIVU()
{
    regAllocReserve(X86::EAX);
    regAllocReserve(X86::EDX);

    RegNum src1 = inst_->getOperand(1).reg,
	   src2 = inst_->getOperand(2).reg,
	   dst1 = inst_->getOperand(3).reg,
	   dst2 = inst_->getOperand(4).reg;

    assert(src1 != 0 &&
	   src2 != 0 &&
	   dst1 != 0 &&
	   dst2 != 0 );
    
    RegNum Tsrc1 = regAlloc(src1, USE),
	   Tsrc2 = regAlloc(src2, USE),
	   Tdst1 = regAlloc(dst1, DEF),
	   Tdst2 = regAlloc(dst2, DEF);

    // EAX(quotient):EDX(remainder) <- EDX:EAX / reg
    // dst1         :dst2           <- src1    / src2
    X86::movw_reg_to_reg(Tsrc1, X86::EAX);
    X86::movw_imm_to_reg(0, X86::EDX);
    X86::div_edx_eax_by_reg(Tsrc2);
    X86::movw_reg_to_reg(X86::EAX, Tdst1);
    X86::movw_reg_to_reg(X86::EDX, Tdst2);

    regAllocRelease(X86::EDX);
    regAllocRelease(X86::EAX);
}

// CMP cc, v1, v2, v3
void X86Translator::encodeCMP()
{    
    RegNum src1 = inst_->getOperand(2).reg,
	   src2 = inst_->getOperand(3).reg,
	   dst	= inst_->getOperand(4).reg;

    assert(dst != 0);

    RegNum Tsrc1, Tsrc2,
	   // got a problem here, x86::setcc only support r/m8 register.
	   // this is a workaround, any better solution? TODO
	   // FIXME: crash if force use X86::EAX
	   Tdst = regAllocForce(dst, X86::EBX, DEF);
	   // Tdst = regAlloc(dst, DEF);

    // zero Tdst
    //deleted by zhengjuyu
    //X86::xor_reg_to_reg(Tdst, Tdst);

    unsigned char tttn = X86::CCENCODINGS[inst_->getOperand(1).cc];

    if (src1 == 0) {
	//Tsrc1 = regAlloc(src1, USE);
	regAllocReserve( X86::EAX );
	Tsrc2 = regAlloc(src2, USE);
	X86::xor_reg_to_reg(X86::EAX, X86::EAX);
	X86::cmp_reg_with_reg(X86::EAX, Tsrc2);
	regAllocRelease( X86::EAX );
	//X86::cmp_imm_with_reg(src1, Tsrc2);
    }
    else if (src2 == 0) {
	Tsrc1 = regAlloc(src1, USE);
	X86::test_reg_with_reg(Tsrc1, Tsrc1);
    }
    else {
	Tsrc1 = regAlloc(src1, USE);
	Tsrc2 = regAlloc(src2, USE);
	X86::cmp_reg_with_reg(Tsrc1, Tsrc2);
    }

    X86::setcc(Tdst, tttn);
    //added by zhengjuyu
    X86::movzbl_reg_to_reg(Tdst, Tdst);
}

// BRANCH cc, v1, v2, reg, disp
void X86Translator::encodeBRANCH()
{

    int i = addTBlockExit(
		    TBlock::ExitReason::BRANCHTAKEN, 
		    0,	// next: filled in at runtime 
		    0,	// exitOffset: set later
		    inst_);
    TBlock::Exit& e = tblock_->getExit(i);

    // fill in exit.next
    RegNum reg	= inst_->getOperand(4).reg;
    Word   disp	= inst_->getOperand(5).imm;
    if (reg == 0) 
	X86::movw_imm_to_mem(disp, (MemAddr) &(e.next));
    else {
	X86::movw_imm_to_mem(disp, (MemAddr) &(e.next));
	X86::add_reg_to_mem(regAlloc(reg, USE), (MemAddr) &(e.next));
    }

    // conditional branch
    CmpCC cc = inst_->getOperand(1).cc;
    RegNum src1 = inst_->getOperand(2).reg,
	   src2 = inst_->getOperand(3).reg;

    assert(!(src1 == 0 && src2 == 0));

    RegNum Tsrc1, Tsrc2;
    if (src1 == 0) {
	Tsrc2 = regAlloc(src2, USE);
	X86::cmp_imm_with_reg(src1, Tsrc2);
    }
    else if (src2 == 0) {
	Tsrc1 = regAlloc(src1, USE);
	X86::test_reg_with_reg(Tsrc1, Tsrc1);
    }
    else {
	Tsrc1 = regAlloc(src1, USE);
	Tsrc2 = regAlloc(src2, USE);
	X86::cmp_reg_with_reg(Tsrc1, Tsrc2);
    }

    unsigned char tttn = X86::CCENCODINGS[cc];
    X86::jcc_relative_direct_disp32(0, tttn);    // back patched later

    // set exit offset
    e.exitOffset = X86::getP() - 4 - instBuf_;
}


// JMP pc
void X86Translator::encodeJMP()
{
    int i = addTBlockExit(
		    TBlock::ExitReason::BRANCHTAKEN, 
		    0,	// next: filled in at runtime 
		    0,	// exitOffset: set later
		    inst_);

    TBlock::Exit& e = tblock_->getExit(i);

    RegNum  reg	    = inst_->getOperand(1).reg;
    Word    disp    = inst_->getOperand(2).imm;

    if (reg == 0) 
	X86::movw_imm_to_mem(disp, (MemAddr) &(e.next));
    else {
	// register value is evaluated at runtime
	// fill in exit.next
	X86::movw_imm_to_mem(disp, (MemAddr) &(e.next));
	X86::add_reg_to_mem(regAlloc(reg, USE), (MemAddr) &(e.next));
    }

    X86::jmp_relative_direct_disp32(0);    // back patched later
    
    // set exit offset
    e.exitOffset = X86::getP() - 4 - instBuf_;
}

// SYSCALL code
// For platforms with same OS, SYSCALL does not have to exit the current
// TBlock, otherwise we have to exit, to emulate the syscall.
void X86Translator::encodeSYSCALL()
{
    // For SimpleScalar platform, we have to exit the current tblock.
    
    X86::jmp_relative_direct_disp32(0);	// back patched later

    addTBlockExit(
	    TBlock::ExitReason::SYSCALLEXIT,
	    vblock_->nextSPC(),		// next
	    X86::getP() - 4 - instBuf_,	// exitOffset
	    inst_);
}

void X86Translator::encodeSBREAK()
{
    X86::sbreak();
#ifdef DEBUG
    tblock_->addBreakpoint( inst_->getVAddr(), X86::getP() - 1 ); 
#endif
}

void X86Translator::encodeCALL()
{
    Word addr = inst_->getOperand(1).word;
    int num = (int) inst_->getOperand(2).word;	// arguments number

    regAllocReserve(X86::ESP);
    //regAllocReserve(X86::EAX);
    //regAllocReserve(X86::ECX);
    //regAllocReserve(X86::EDX);
    // Word *sp = &callStack_[1023];
    MemAddr sp = (MemAddr)callStack_ + sizeof(callStack_) - sizeof(Word);

    X86::movw_reg_to_mem(X86::ESP, sp);		// save old ESP
    X86::movw_imm_to_reg(sp, X86::ESP);		// use simulated stack

    // save EAX, EDX, ECX, according to x86 function calling ABI
    // these three registers should be saved by caller
    X86::push_reg(X86::EAX);
    X86::push_reg(X86::EDX);
    X86::push_reg(X86::ECX);

    // push function arguments from RIGHT to LEFT
    for (int i = num + 2; i > 2; i--) {
	RegNum reg = inst_->getOperand(i).reg;	
	//X86::push_reg(regAlloc(reg,USE));
	X86::push_reg(regAllocForCall(reg,USE));
	//Word arg = inst_->getOperand(i).word;
	//X86::push_imm32(arg);
    }

    X86::call_relative_direct_disp32(addr - (Word)(X86::getP() + 5));
    tblock_->addRelocationPoint((X86::getP() - 4) - instBuf_);

    // pop the function arguments
    X86::add_imm_to_reg(num * sizeof(Word), X86::ESP);
   
    // restore EAX, EDX, ECX
    X86::pop_reg(X86::ECX);
    X86::pop_reg(X86::EDX);
    X86::pop_reg(X86::EAX);

    // restore ESP
    X86::pop_reg(X86::ESP);

    //regAllocRelease(X86::EDX);
    //regAllocRelease(X86::ECX);
    //regAllocRelease(X86::EAX);
    regAllocRelease(X86::ESP);
}

void X86Translator::encodeLOOP()
{
    RegNum reg = inst_->getOperand(1).reg;
    Word id = inst_->getOperand(2).imm;
    Word forward = inst_->getOperand(3).imm;
    
    // regAllocForce(reg, X86::ECX, USE);

    X86::cmp_imm_with_reg(0, regAlloc(reg, USE));
    X86::je_relative_direct_disp32(0);
    //X86::jecxz(0);
    loopAddr[id] = (Word)(X86::getP() - 4);

    if (forward == 0)
    {	
	assert(labelAddr[id] != -1);

	int* p = (int*)(loopAddr[id]);
	*p = (int)(labelAddr[id] - loopAddr[id] - 4);

	loopAddr[id] = -1;
    }
}

void X86Translator::encodeLOOPN()
{
    RegNum reg = inst_->getOperand(1).reg;
    Word id = inst_->getOperand(2).imm;
    Word forward = inst_->getOperand(3).imm;
    
    X86::cmp_imm_with_reg(0, regAlloc(reg, USE));
    X86::jne_relative_direct_disp32(0);

    loopAddr[id] = (Word)(X86::getP() - 4);

    if (forward == 0)
    {	
	assert(labelAddr[id] != -1);

	int* p = (int*)(loopAddr[id]);
	*p = (int)(labelAddr[id] - loopAddr[id] - 4);

	loopAddr[id] = -1;
    }
}

void X86Translator::encodeLABEL()
{
    Word id = inst_->getOperand(1).imm;
    
    labelAddr[id] = (Word)(X86::getP());
    if (loopAddr[id] != -1)
    {
	int* p = (int*) (loopAddr[id]);
	*p = (int)(labelAddr[id] - loopAddr[id] - 4);

	loopAddr[id] = -1;
    }
}

void X86Translator::encodeUSE() {
    RegNum  reg	= inst_->getOperand(1).reg;
    regAllocForceExcept(reg, X86::ESP, USE);
}

// float point encoding added
void X86Translator::encodeFPUTS(){
    MemAddr addr = srcState_->fpget(inst_->getOperand(1).reg);
    X86::fp_pop_freg32(addr);
}

void X86Translator::encodeFGETS(){
    MemAddr addr = srcState_->fpget(inst_->getOperand(1).reg);
    X86::fp_push_freg32(addr);
}

void X86Translator::encodeFPUTD(){
    regAllocReserve(X86::EAX);
    regAllocReserve(X86::EDX);
     	MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
	X86::fldcw( tempaddr );

    RegNum src = inst_->getOperand(1).reg;

    RegNum Tsrc = regAlloc(src, USE);

    MemAddr offset = srcState_->fpget(1) - srcState_->fpget(0);
    X86::movw_imm_to_reg(offset, X86::EAX);
    X86::mul_eax_to_reg(Tsrc);

    MemAddr addr = srcState_->fpget(0);
    X86::fp_pop_freg64_base_disp(X86::EAX, addr);

    regAllocRelease(X86::EDX);
    regAllocRelease(X86::EAX);
}

void X86Translator::encodeFGETD(){
    regAllocReserve(X86::EAX);
    regAllocReserve(X86::EDX);
     	MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
	X86::fldcw( tempaddr );

    RegNum src = inst_->getOperand(1).reg;

    RegNum Tsrc = regAlloc(src, USE);

    MemAddr offset = srcState_->fpget(1) - srcState_->fpget(0);
    X86::movw_imm_to_reg(offset, X86::EAX);
    X86::mul_eax_to_reg(Tsrc);

    MemAddr addr = srcState_->fpget(0);
    X86::fp_push_freg64_base_disp(X86::EAX, addr);

    regAllocRelease(X86::EDX);
    regAllocRelease(X86::EAX);
}

/*
void X86Translator::encodeFLD(){
    RegNum	reg	= inst_->getOperand(1).reg;
    Word	disp	= inst_->getOperand(2).imm;
    BlockSize	size	= inst_->getOperand(3).size;
    RegNum	dst	= inst_->getOperand(4).reg;

// notice: float-point registers are stack-based and 
// can not apply register allocation police. This FLD
// instruction will cause a mem_to_mem copy operation.
   // MemAddr addr = srcState_->reg(reg) + disp;
    if(size == WORD){
    	//X86::fp_push_freg32(addr);
	MemAddr dstaddr = srcState_->fpget(dst);
	regAllocReserve( X86::ECX );
	
	if( reg != 0 )
	{
	    RegNum srcreg = regAllocForceExcept( reg, X86::ESP, USE );
	    X86::mov_mem_to_reg(srcreg, disp, size, X86::ECX);
	    X86::mov_reg_to_mem( X86::ECX, size, dstaddr); 
	}
	else
	{
	    X86::movw_mem_to_reg(disp, X86::ECX);
	    X86::mov_reg_to_mem( X86::ECX, size, dstaddr); 
	}
	regAllocRelease( X86::ECX );
    }
    else{
    	//X86::fp_push_freg64(addr);
	MemAddr dstaddr = srcState_->fpget(dst);
	regAllocReserve( X86::ECX );

	if( reg != 0 )
	{
	    RegNum srcreg = regAllocForceExcept( reg, X86::ESP, USE );
	    X86::mov_mem_to_reg( srcreg, disp, WORD, X86::ECX );
	    X86::mov_reg_to_mem( X86::ECX, WORD, dstaddr);
	    X86::mov_mem_to_reg( srcreg, disp + 4, WORD, X86::ECX );
	    X86::mov_reg_to_mem( X86::ECX, WORD, dstaddr + 4);
	}
	else 
	{
	    X86::movw_mem_to_reg( disp, X86::ECX );
	    X86::mov_reg_to_mem( X86::ECX, WORD, dstaddr );
	    X86::movw_mem_to_reg( disp + 4, X86::ECX );
	    X86::mov_reg_to_mem( X86::ECX, WORD, dstaddr+4);
	}

	regAllocRelease( X86::ECX );
    }
}
*/

// New encodeFLD()
// In the old version, the fourth param is the real float register number.
// In the new version, the fourth param is a virtual registers number,
// it stores the destination float register's number.
void X86Translator::encodeFLD(){
    RegNum	reg	= inst_->getOperand(1).reg;
    Word	disp	= inst_->getOperand(2).imm;
    BlockSize	size	= inst_->getOperand(3).size;
    RegNum	dst	= inst_->getOperand(4).reg;

    if(size == WORD){
    	//X86::fp_push_freg32(addr);
	MemAddr dstaddr = srcState_->fpget(0);
	regAllocReserve( X86::EDX );
	regAllocReserve( X86::EAX );

	MemAddr offset = srcState_->fpget(1) - srcState_->fpget(0);	
	X86::movw_imm_to_reg(offset, X86::EAX);
	RegNum Tdst = regAlloc(dst, USE);
	X86::mul_eax_to_reg(Tdst);

	if( reg != 0 )
	{
	    RegNum srcreg = regAllocForceExcept( reg, X86::ESP, USE );
	    X86::mov_mem_to_reg(srcreg, disp, size, X86::EDX);
	    X86::mov_reg_to_mem( X86::EDX, size, X86::EAX, dstaddr); 
	}
	else
	{
	    X86::movw_mem_to_reg(disp, X86::EDX);
	    X86::mov_reg_to_mem( X86::EDX, size, X86::EAX, dstaddr); 
	}
	regAllocRelease( X86::EAX );
	regAllocRelease( X86::EDX );
    }
    else{
    	//X86::fp_push_freg64(addr);
	MemAddr dstaddr = srcState_->fpget(0);
	regAllocReserve( X86::EDX );
	regAllocReserve( X86::EAX );

	MemAddr offset = srcState_->fpget(1) - srcState_->fpget(0);	
	X86::movw_imm_to_reg(offset, X86::EAX);
	RegNum Tdst = regAllocForceExcept(dst, X86::EDX, USE);
	X86::mul_eax_to_reg(Tdst);

	if( reg != 0 )
	{
	    RegNum srcreg = regAllocForceExcept( reg, X86::ESP, USE );
	    X86::mov_mem_to_reg( srcreg, disp, WORD, X86::EDX );
	    X86::mov_reg_to_mem( X86::EDX, WORD, X86::EAX, dstaddr);
	    X86::mov_mem_to_reg( srcreg, disp + 4, WORD, X86::EDX );
	    X86::mov_reg_to_mem( X86::EDX, WORD, X86::EAX, dstaddr + 4);
	}
	else 
	{
	    X86::movw_mem_to_reg( disp, X86::EDX );
	    X86::mov_reg_to_mem( X86::EDX, WORD, X86::EAX, dstaddr );
	    X86::movw_mem_to_reg( disp + 4, X86::EDX );
	    X86::mov_reg_to_mem( X86::EDX, WORD, X86::EAX, dstaddr+4);
	}

	regAllocRelease( X86::EAX );
	regAllocRelease( X86::EDX );
    }
}

/*
void X86Translator::encodeFST(){
    RegNum	src	= inst_->getOperand(1).reg;
    BlockSize	size	= inst_->getOperand(2).size;
    RegNum	reg	= inst_->getOperand(3).reg;
    Word	disp	= inst_->getOperand(4).imm;
    regAllocReserve(X86::ECX);
    //20 is magic
    //RegNum srcreg = regAllocForceExcept(20, X86::ESP, DEF);
    RegNum dstreg = regAllocForceExcept( reg, X86::ESP, USE);
    
    MemAddr srcaddr = srcState_->fpget(src);
  
    if(size == WORD){
	X86::movw_mem_to_reg( srcaddr, X86::ECX);
	
	if(reg == 0 )
	{
	    X86::mov_reg_to_mem( X86::ECX, size, disp);
	}
	else
	{
	    X86::mov_reg_to_mem( X86::ECX, size, dstreg, disp);
	}
    }
    else{
	X86::movw_mem_to_reg( srcaddr, X86::ECX );

	if( reg == 0 )
	{
    	    X86::mov_reg_to_mem( X86::ECX, WORD, disp );
	    X86::movw_mem_to_reg( srcaddr + 4, X86::ECX );
	    X86::mov_reg_to_mem( X86::ECX, WORD, disp + 4);
	}
	else
	{
	    X86::mov_reg_to_mem( X86::ECX, WORD, dstreg, disp );
	    X86::movw_mem_to_reg( srcaddr + 4,  X86::ECX );
	    X86::mov_reg_to_mem( X86::ECX, WORD, dstreg, disp +4);
	}	    
    }
    regAllocRelease(X86::ECX);
}
*/

// New encodeFST()
// In the old version, the first param is the float register number.
// In the new version, the first param is a virtual registers, it stores
// the float registers' number.
void X86Translator::encodeFST(){
    RegNum	src	= inst_->getOperand(1).reg;
    BlockSize	size	= inst_->getOperand(2).size;
    RegNum	reg	= inst_->getOperand(3).reg;
    Word	disp	= inst_->getOperand(4).imm;

    //regAllocReserve(X86::ECX);
    regAllocReserve(X86::EAX);
    regAllocReserve(X86::EDX);

    RegNum dstreg = regAllocForceExcept( reg, X86::ESP, USE);
    
    RegNum Tsrc = regAlloc(src, USE);

    MemAddr srcaddr = srcState_->fpget(0);
    MemAddr offset = srcState_->fpget(1) - srcState_->fpget(0);
    X86::movw_imm_to_reg(offset, X86::EAX);
    X86::mul_eax_to_reg(Tsrc);
  
    if(size == WORD){
	X86::mov_mem_to_reg( X86::EAX, srcaddr, WORD, X86::EDX);
	
	if(reg == 0 )
	{
	    X86::mov_reg_to_mem( X86::EDX, size, disp);
	}
	else
	{
	    X86::mov_reg_to_mem( X86::EDX, size, dstreg, disp);
	}
    }
    else{
	X86::mov_mem_to_reg( X86::EAX, srcaddr, WORD, X86::EDX );

	if( reg == 0 )
	{
    	    X86::mov_reg_to_mem( X86::EDX, WORD, disp );
	    X86::mov_mem_to_reg( X86::EAX, srcaddr + 4, WORD, X86::EDX );
	    X86::mov_reg_to_mem( X86::EDX, WORD, disp + 4);
	}
	else
	{
	    X86::mov_reg_to_mem( X86::EDX, WORD, dstreg, disp );
	    X86::mov_mem_to_reg( X86::EAX, srcaddr + 4, WORD, X86::EDX );
	    X86::mov_reg_to_mem( X86::EDX, WORD, dstreg, disp +4);
	}	    
    }

    regAllocRelease(X86::EDX);
    regAllocRelease(X86::EAX);
    //regAllocRelease(X86::ECX);
}
 
void X86Translator::encodeFMOV(){

}

void X86Translator::encodeFCOS(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_fcos();
}

void X86Translator::encodeFPTAN(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_fptan();
}

void X86Translator::encodeFSIN(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_fsin();
}

void X86Translator::encodeFCHS(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_fchs();
}

void X86Translator::encodeFSCALE(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_fscale();
}

void X86Translator::encodeF2XM1(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_f2xm1();
}

void X86Translator::encodeFYL2XP1(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_fyl2xp1();
}

void X86Translator::encodeFYL2X(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_fyl2x();
}

void X86Translator::encodeFLDL2E(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_fldl2e();
}

void X86Translator::encodeFLDLN2(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_fldln2();
}

void X86Translator::encodeFLDLG2(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_fldlg2();
}

void X86Translator::encodeFRNDINT(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );
    X86::fp_frndint();
}

void X86Translator::encodeFXAM(){
    regAllocReserve(X86::EAX);

    	MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
	X86::fldcw( tempaddr );

    X86::fp_fxam();
    X86::fnstsw();

    tempaddr = srcState_->fpget(11);
    X86::movw_reg_to_mem(X86::EAX, tempaddr);

    regAllocRelease(X86::EAX);
}

void X86Translator::encodeFADDS(){
    X86::fp_add32();
}
 
void X86Translator::encodeFADDD(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_add64();
}
            
void X86Translator::encodeFSUBS(){
    X86::fp_sub32();
}
            
void X86Translator::encodeFSUBD(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_sub64();
}
            
void X86Translator::encodeFMULS(){
	X86::fp_mult32();
}
            
void X86Translator::encodeFMULD(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

	X86::fp_mult64();
}
            
void X86Translator::encodeFDIVS(){
	X86::fp_div32();
}
            
void X86Translator::encodeFDIVD(){
    MemAddr tempaddr = srcState_->get( 22 );
    X86::fldcw( tempaddr );

    X86::fp_div64();
}

void X86Translator::encodeFNEGS(){
	X86::fp_chs();
}
            
void X86Translator::encodeFNEGD(){
    	MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
	X86::fldcw( tempaddr );

	X86::fp_chs();
}
            
void X86Translator::encodeFABSS(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fabs();
}
            
void X86Translator::encodeFABSD(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fabs();
}
            
void X86Translator::encodeFSQRTS(){
    X86::fp_sqrt();
}
            
void X86Translator::encodeFSQRTD(){
    MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
    X86::fldcw( tempaddr );

    X86::fp_sqrt();
}
            
void X86Translator::encodeFCMPS(){
    MemAddr srcaddr1 = srcState_->fpget(inst_->getOperand(2).reg);
    MemAddr srcaddr2 = srcState_->fpget(inst_->getOperand(3).reg);
    MemAddr dstaddr = srcState_->fpget(inst_->getOperand(4).reg);
    
    X86::fp_push_freg32(srcaddr2);
    X86::fp_push_freg32(srcaddr1);
    X86::fcmp_fpreg_with_fpreg_pop();

    unsigned char tttn = X86::CCENCODINGS[inst_->getOperand(1).cc];

    regAllocReserve( X86::EBX );

    X86::setcc(X86::EBX, tttn);
    X86::mov_reg_to_mem(X86::EBX, BYTE, dstaddr);

    X86::fincstp();
    X86::fincstp();

    regAllocRelease( X86::EBX );
}
 
/*
void X86Translator::encodeFCMPD(){
    MemAddr srcaddr1 = srcState_->fpget(inst_->getOperand(2).reg);
    MemAddr srcaddr2 = srcState_->fpget(inst_->getOperand(3).reg);
    MemAddr dstaddr = srcState_->fpget(inst_->getOperand(4).reg);

    unsigned char tttn = X86::CCENCODINGS[inst_->getOperand(1).cc];
    
    regAllocReserve(X86::EBX);
    
    X86::fp_push_freg64(srcaddr2);
    X86::fp_push_freg64(srcaddr1);
    X86::fcmp_fpreg_with_fpreg_pop();
    
    X86::setcc(X86::EBX, tttn);
    X86::mov_reg_to_mem(X86::EBX, BYTE, dstaddr);
    
    X86::fincstp();
    X86::fincstp();
 
    regAllocRelease( X86::EBX );
}
*/

// New encodeFCMPD()
// Use virutal register instead of real register number.
void X86Translator::encodeFCMPD(){
    MemAddr srcaddr1 = srcState_->fpget(inst_->getOperand(2).reg);
    MemAddr srcaddr2 = srcState_->fpget(inst_->getOperand(3).reg);
    MemAddr dstaddr = srcState_->fpget(inst_->getOperand(4).reg);

    unsigned char tttn = X86::CCENCODINGS[inst_->getOperand(1).cc];
    
    MemAddr offset = srcState_->fpget(1) - srcState_->fpget(0);
    MemAddr srcaddr = srcState_->fpget(0);

    	MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
	X86::fldcw( tempaddr );

    regAllocReserve(X86::EAX);
    regAllocReserve(X86::EBX);
    regAllocReserve(X86::EDX);

    X86::movw_imm_to_reg(offset, X86::EAX);
    RegNum Tsrc1 = regAlloc(inst_->getOperand(3).reg, USE);
    X86::mul_eax_to_reg(Tsrc1);
    
    X86::fp_push_freg64_base_disp(X86::EAX, srcaddr);
    
    X86::movw_imm_to_reg(offset, X86::EAX);
    RegNum Tsrc2 = regAlloc(inst_->getOperand(2).reg, USE);
    X86::mul_eax_to_reg(Tsrc2);
    X86::fp_push_freg64_base_disp(X86::EAX, srcaddr);

    X86::fcmp_fpreg_with_fpreg_pop();
    X86::setcc(X86::EBX, tttn);
    
    //X86::movw_imm_to_reg(offset, X86::EAX);
    //RegNum Tdst = regAlloc(inst_->getOperand(4).reg, USE);
    //X86::mul_eax_to_reg(Tdst);

    X86::mov_reg_to_mem(X86::EBX, BYTE, dstaddr);
    //X86::mov_reg_to_mem(X86::EBX, BYTE, X86::EAX, srcaddr);
 
    X86::fincstp();
 
    regAllocRelease( X86::EDX );
    regAllocRelease( X86::EBX );
    regAllocRelease( X86::EAX );
}

/*
void X86Translator::encodeFCONV(){
    RegNum	src	= inst_->getOperand(1).reg;
    BlockSize	srcsize	= inst_->getOperand(2).size;
    RegNum	dst	= inst_->getOperand(3).reg;
    BlockSize	dstsize	= inst_->getOperand(4).size;

    MemAddr srcaddr = srcState_->fpget(src);
    MemAddr dstaddr = srcState_->fpget(dst);

    if (srcsize == FLOAT && dstsize == DOUBLE){
    	X86::fp_push_freg32(srcaddr);
    	X86::fp_pop_freg64(dstaddr);}
    else if (srcsize == DOUBLE && dstsize == FLOAT){
    	X86::fp_push_freg64(srcaddr);
    	X86::fp_pop_freg32(dstaddr);}
    else if (srcsize == FLOAT && dstsize == FLOAT){
    	X86::fp_push_freg32(srcaddr);
    	X86::fp_pop_freg32(dstaddr);}
    else if (srcsize == DOUBLE && dstsize == DOUBLE){
	X86::fp_push_freg64(srcaddr); 
    	X86::fp_pop_freg64(dstaddr);}
    else if (srcsize == WORD && dstsize == FLOAT){
	X86::int_push_freg32(srcaddr);
    	X86::fp_pop_freg32(dstaddr);}
    else if (srcsize == WORD && dstsize == DOUBLE){
	X86::int_push_freg32(srcaddr);
    	X86::fp_pop_freg64(dstaddr);}
    else if (srcsize == DWORD && dstsize == DOUBLE){
	X86::longlong_push_freg64(srcaddr);
    	X86::fp_pop_freg64(dstaddr);}
    else if (srcsize == FLOAT && dstsize == WORD){
	
	//set the FPU's control word RC to truncat mode	

	regAllocReserve(X86::ECX);
	MemAddr tempaddr = srcState_->fpget( 33 ); //PISAState::$fcw );
	
	X86::fstcw( tempaddr );

	X86::mov_mem_to_reg( tempaddr, HALFWORD, X86::ECX );
	X86::and_imm_to_reg( 0xf7ff, X86::ECX );
	X86::or_imm_to_reg( 0xc00, X86::ECX );
	X86::mov_reg_to_mem( X86::ECX, HALFWORD, tempaddr );
	
	X86::fldcw( tempaddr );
	
	regAllocRelease(X86::ECX);
	
	X86::fp_push_freg32(srcaddr);
    	X86::int_pop_freg32(dstaddr);}
    else if (srcsize == DOUBLE && dstsize == WORD){
	//set the FPU's control word RC to trancat mode
	regAllocReserve(X86::ECX);
	MemAddr tempaddr = srcState_->fpget( 33 ); //PISAState::$fcw );
	
	X86::fstcw( tempaddr );

	X86::mov_mem_to_reg( tempaddr, HALFWORD, X86::ECX );
	X86::and_imm_to_reg( 0xf7ff, X86::ECX );
	X86::or_imm_to_reg( 0xc00, X86::ECX );
	X86::mov_reg_to_mem( X86::ECX, HALFWORD, tempaddr );
	
	X86::fldcw( tempaddr );
	
	regAllocRelease(X86::ECX);
	
	X86::fp_push_freg64((MemAddr)srcaddr);
    	X86::int_pop_freg32(dstaddr);}
    else if (srcsize == WORD && dstsize == WORD){
	X86::int_push_freg32((MemAddr)srcaddr);
    	X86::int_pop_freg32(dstaddr);}
}
*/

//New encodeFCONV()
//Use virutal register instead of real register number.
void X86Translator::encodeFCONV(){
    RegNum	src	= inst_->getOperand(1).reg;
    BlockSize	srcsize	= inst_->getOperand(2).size;
    RegNum	dst	= inst_->getOperand(3).reg;
    BlockSize	dstsize	= inst_->getOperand(4).size;

    MemAddr srcaddr = srcState_->fpget(0);
    MemAddr dstaddr = srcState_->fpget(0);

    regAllocReserve(X86::EAX);
    regAllocReserve(X86::EDX);
    
    	MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
	X86::fldcw( tempaddr );

    MemAddr offset = srcState_->fpget(1) - srcState_->fpget(0);

    if (srcsize == FLOAT && dstsize == DOUBLE) {
	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(src, USE));
    	X86::fp_push_freg32_base_disp(X86::EAX, srcaddr);

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(dst, USE));
    	X86::fp_pop_freg64_base_disp(X86::EAX, dstaddr);
    } else if (srcsize == DOUBLE && dstsize == FLOAT) {
	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(src, USE));
    	X86::fp_push_freg64_base_disp(X86::EAX, srcaddr);

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(dst, USE));
    	X86::fp_pop_freg32_base_disp(X86::EAX, dstaddr);
    } else if (srcsize == FLOAT && dstsize == FLOAT) {
	/*
	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(src, USE));
    	X86::fp_push_freg32_base_disp(X86::EAX, srcaddr);

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(dst, USE));
    	X86::fp_pop_freg32_base_disp(X86::EAX, dstaddr);
	*/
	printf("Unimplemented encodeFCONV\n");
	exit(0);

    } else if (srcsize == DOUBLE && dstsize == DOUBLE) {
	/*
	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(src, USE));
    	X86::fp_push_freg64_base_disp(X86::EAX, srcaddr);

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(dst, USE));
    	X86::fp_pop_freg64_base_disp(X86::EAX, dstaddr);
	*/
	printf("Unimplemented encodeFCONV\n");
	exit(0);

    } else if (srcsize == WORD && dstsize == FLOAT) {
	/*
	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(src, USE));
    	X86::int_push_freg32_base_disp(X86::EAX, srcaddr);

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(dst, USE));
    	X86::fp_pop_freg32_base_disp(X86::EAX, dstaddr);
	*/
	printf("Unimplemented encodeFCONV\n");
	exit(0);
    } else if (srcsize == HALFWORD && dstsize == DOUBLE) {
	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(src, USE));
    	X86::int_push_freg16_base_disp(X86::EAX, srcaddr);

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(dst, USE));
    	X86::fp_pop_freg64_base_disp(X86::EAX, dstaddr);
    } else if (srcsize == WORD && dstsize == DOUBLE) {
	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(src, USE));
    	X86::int_push_freg32_base_disp(X86::EAX, srcaddr);

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(dst, USE));
    	X86::fp_pop_freg64_base_disp(X86::EAX, dstaddr);
    } else if (srcsize == DWORD && dstsize == DOUBLE) {
	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(src, USE));
    	X86::longlong_push_freg64_base_disp(X86::EAX, srcaddr);

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(dst, USE));
    	X86::fp_pop_freg64_base_disp(X86::EAX, dstaddr);
    } else if (srcsize == FLOAT && dstsize == WORD) {
	/*
	//set the FPU's control word RC to truncat mode	

	regAllocReserve(X86::ECX);
	MemAddr tempaddr = srcState_->fpget( 33 ); //PISAState::$fcw );
	
	X86::fstcw( tempaddr );

	X86::mov_mem_to_reg( tempaddr, HALFWORD, X86::ECX );
	X86::and_imm_to_reg( 0xf7ff, X86::ECX );
	X86::or_imm_to_reg( 0xc00, X86::ECX );
	X86::mov_reg_to_mem( X86::ECX, HALFWORD, tempaddr );
	
	X86::fldcw( tempaddr );
	
	regAllocRelease(X86::ECX);
	
	X86::fp_push_freg32(srcaddr);
    	X86::int_pop_freg32(dstaddr);}
	*/
	printf("Unimplemented encodeFCONV\n");
	exit(0);
    } else if (srcsize == DOUBLE && dstsize == WORD) {
	//set the FPU's control word RC to trancat mode
	MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
	X86::fldcw( tempaddr );

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(src, USE));
	X86::fp_push_freg64_base_disp(X86::EAX, (MemAddr)srcaddr);

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(dst, USE));

    	X86::int_pop_freg32_base_disp(X86::EAX, dstaddr);
    } else if (srcsize == DOUBLE && dstsize == DWORD) {
	MemAddr tempaddr = srcState_->get( 22 ); //PISAState::$fcw );
	X86::fldcw( tempaddr );

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(src, USE));
	X86::fp_push_freg64_base_disp(X86::EAX, (MemAddr)srcaddr);

	X86::movw_imm_to_reg(offset, X86::EAX);
	X86::mul_eax_to_reg(regAlloc(dst, USE));
    	X86::longlong_pop_freg64_base_disp(X86::EAX, dstaddr);
    } else if (srcsize == WORD && dstsize == WORD) {
	    /*
	X86::int_push_freg32((MemAddr)srcaddr);
    	X86::int_pop_freg32(dstaddr);
	*/
	printf("Unimplemented encodeFCONV\n");
	exit(0);
    }

    regAllocRelease(X86::EDX);
    regAllocRelease(X86::EAX);
}

void X86Translator::encodeFINCSTP()
{
    X86::fincstp();
}

void X86Translator::encodeBSF()
{
    RegNum	src	= inst_->getOperand(1).reg;
    RegNum	dst	= inst_->getOperand(2).reg;

    RegNum Tsrc = regAlloc (src, USE);
    RegNum Tdst = regAlloc (dst, DEF);

    X86::bsf(Tsrc, Tdst);
}

void X86Translator::encodeBSR()
{
    RegNum	src	= inst_->getOperand(1).reg;
    RegNum	dst	= inst_->getOperand(2).reg;

    RegNum Tsrc = regAlloc (src, USE);
    RegNum Tdst = regAlloc (dst, DEF);

    X86::bsr(Tsrc, Tdst);
}

void X86Translator::encodeDIVU64()
{
    regAllocReserve(X86::EAX);
    regAllocReserve(X86::EDX);

    RegNum src1 = inst_->getOperand(1).reg,
	   src2 = inst_->getOperand(2).reg,
	   src3 = inst_->getOperand(3).reg,
	   dst1 = inst_->getOperand(4).reg,
	   dst2 = inst_->getOperand(5).reg;

    assert(src1 != 0 &&
	   src2 != 0 &&
	   src3 != 0 &&
	   dst1 != 0 &&
	   dst2 != 0 );
    
    RegNum Tsrc1 = regAlloc(src1, USE),
	   Tsrc2 = regAlloc(src2, USE),
	   Tsrc3 = regAlloc(src3, USE),
	   Tdst1 = regAlloc(dst1, DEF),
	   Tdst2 = regAlloc(dst2, DEF);

    // EAX(quotient):EDX(remainder) <- EDX:EAX / reg
    // dst1         :dst2           <- src1    / src2
    X86::movw_reg_to_reg(Tsrc1, X86::EAX);
    X86::movw_reg_to_reg(Tsrc2, X86::EDX);
    X86::div_edx_eax_by_reg(Tsrc3);
    X86::movw_reg_to_reg(X86::EAX, Tdst1);
    X86::movw_reg_to_reg(X86::EDX, Tdst2);

    regAllocRelease(X86::EDX);
    regAllocRelease(X86::EAX);
}

Word * X86Translator::allocfpWord(Word src){
	fpWordcache_[fpWordcount]=src;
	return &fpWordcache_[fpWordcount++];
}

DWord * X86Translator::allocfpDword(DWord src){
	fpDwordcache_[fpDwordcount]=src;
	return &fpDwordcache_[fpDwordcount++];
}
